/*
    日志缓冲区类
*/

#pragma once
#include <iostream>
#include <vector>
#include <cassert>

namespace easylog
{
    #define DEFAULT_BUFFER_SIZE (10 * 1024 * 1024)
    #define DEFAULT_THRESHOLD_SIZE (80 * 1024 * 1024)
    #define DEFAULT_INCREMENT_SIZE (10 * 1024 * 1024)
    //扩容类型
    enum class ReserveType
    {
        CLOG = 0,//阻塞
        RESERVE//扩容
    };
    //缓冲区
    class Buffer
    {
    public:
        Buffer(const size_t cap = DEFAULT_BUFFER_SIZE, 
               const size_t threshold = DEFAULT_THRESHOLD_SIZE,
               const size_t increment = DEFAULT_INCREMENT_SIZE,
               ReserveType type = ReserveType::CLOG)
        :_cap(cap), _threshold(threshold), 
        _increment(increment), _read_idx(0),
        _write_idx(0), _isAbleReserve(type)
        {
            _buffer.resize(_cap);
        }
        //写入数据
        void push(const char* data, size_t len)
        {
            //根据标记，选择是否扩容，不扩容直接退出
            if(_isAbleReserve == ReserveType::RESERVE)
            {
                while(len > writeAbleSize())
                    reserve();
            }
            else
            {
                if(len > writeAbleSize())
                    return;
            }
                
            //写入数据
            std::copy(data, data + len, &_buffer[_write_idx]);
            //向后移动写指针
            moveWriter(len);
        }
        //返回可写空间大小
        size_t writeAbleSize() { return _cap - _write_idx; }
        //返回可读数据起始位置
        const char* readBegin() { return &_buffer[_read_idx]; }
        //对读指针进行向后偏移操作
        void moveReader(size_t len)
        {
            assert(len <= readAbleSize());
            _read_idx += len;
        }
        //返回可读数据长度
        size_t readAbleSize() { return _write_idx - _read_idx; }
        //重置缓冲区，重置读写位置
        void reset() { _write_idx = _read_idx = 0; }
        //交换缓冲区
        void swap(Buffer& buffer)
        {
            _buffer.swap(buffer._buffer);
            std::swap(_cap, buffer._cap);
            std::swap (_read_idx, buffer._read_idx);
            std::swap(_write_idx, buffer._write_idx);
            std::swap(_increment, buffer._increment);
            std::swap(_threshold, buffer._threshold);
        }
        //改变是否允许扩容
        void changeIsAbleReserve(ReserveType type) { _isAbleReserve = type; }
        //判断缓冲区是否为空
        bool empty() { return (_write_idx == _read_idx); }
    private:
        //扩容
        void reserve()
        {
            if(_cap < _threshold) _cap *= 2;
            else  _cap += _increment;
            _buffer.resize(_cap);
        }
        //对写指针进行向后偏移操作
        void moveWriter(size_t len)
        {
            assert(len <= writeAbleSize());
            _write_idx += len;
        }
        
    private:
        std::vector<char> _buffer;
        size_t _read_idx;//读指针——本质是下标
        size_t _write_idx;//写指针——本质是下标
        size_t _cap;//当前容量
        size_t _increment;//扩容增量
        size_t _threshold;//扩容阈值
        ReserveType _isAbleReserve;//是否允许扩容标记
    };
}
